package PrjWsMQ

import (
	"dgo/goutils/utils"
	"time"

	"golang.org/x/net/websocket"
)

type WsClient struct {
	ws_req_url string
	origin_url string
	connected  int

	terminated int
	startDNA   int
	conn       *WsConnEx
	dismsg     string
	OnRecv     func(sender *WsClient, msgtype byte, data []byte)
	OnDis      func(sender *WsClient)
	OnConnect  func(sender *WsClient)
}

func NewWsClient(ws_req_url, origin_url string) *WsClient {
	rval := &WsClient{
		ws_req_url: ws_req_url,
		origin_url: origin_url,
	}
	return rval
}

func (this *WsClient) CheckConnect() bool {
	if this.conn != nil {
		return true
	}

	con, err := websocket.Dial(this.ws_req_url, "", this.origin_url)
	if err != nil {
		golog.Debugf("连接服务器(%s)异常:%s", this.ws_req_url, err.Error())
		return false
	}
	this.conn = WrapperWsConnEx(con)
	if this.OnConnect != nil {
		this.OnConnect(this)
	}
	this.connected = 1
	return true
}

func (this *WsClient) IsConnected() bool {
	return this.connected == 1
}

func (this *WsClient) disconnect() {
	if this.conn == nil {
		return
	}

	this.conn.Close()
	if this.OnDis != nil {
		this.OnDis(this)
	}
	this.connected = 0
	this.conn = nil
}

func (this *WsClient) Stop() {
	this.terminated = 1
	this.disconnect()
	this.startDNA++
}

func (this *WsClient) Start() {
	this.terminated = 0
	this.startDNA++
	dna := this.startDNA
	utils.AddTaskAfterInterval("WS_PING", time.Second, time.Second*10, func() bool {
		if this.conn == nil {
			return true
		}
		go SendWsPING(this.conn)
		return dna == this.startDNA
	})

	utils.AddTaskAfterInterval("CHECKPONG", time.Second, time.Second*15, func() bool {
		conn := this.conn
		if conn == nil {
			return true
		}
		if conn.CheckTimeOut(time.Second * 15) {
			conn.Close()
		}
		return dna == this.startDNA
	})
	for {
		if this.terminated == 1 {
			break
		}

		if !this.CheckConnect() {
			time.Sleep(time.Second * 10)
			continue
		}

		msgtype, msg, err := this.receive()
		if err != nil {
			if len(this.dismsg) != 0 {
				this.dismsg = err.Error()
			}
			this.disconnect()
			continue
		}

		if this.OnRecv != nil {
			this.OnRecv(this, msgtype, msg)
		}
	}
	this.disconnect()
}

func (this *WsClient) SendMsg(msgtype byte, msg []byte) error {
	err := SendWsMessage(this.conn, msgtype, msg)
	if err != nil {
		if this.conn != nil {
			this.conn.Close()
		}
	}
	return err
}

func (this *WsClient) receive() (msgtype byte, msg []byte, err error) {
	return ReceiveMessage(this.conn)
}
